home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / sml_nj / 93src.lha / src / modules / sigmatch.sml < prev   
Encoding:
Text File  |  1993-01-27  |  18.9 KB  |  478 lines

  1. (* modules/sigmatch.sml *)
  2.  
  3. signature SIGMATCH = sig
  4.   val match :
  5.     {abstract:bool,
  6.      arg_option: Modules.structureVar option,
  7.      err:ErrorMsg.complainer,
  8.      scope:Stamps.scope,
  9.      spath : Modules.spath,
  10.      printEnv: Modules.env,
  11.      self:bool,
  12.      sign:Modules.Signature,
  13.      str:Modules.Structure} 
  14.     -> Modules.Structure * Modules.thinning
  15.   val matchFct :
  16.     {abstract:bool,
  17.      err:ErrorMsg.complainer,
  18.      scope:Stamps.scope,
  19.      spath : Modules.spath,
  20.      printEnv: Modules.env,
  21.      self:bool,
  22.      fsig:Modules.FctSignature, fct:Modules.Functor} 
  23.     -> Modules.Functor * Modules.fctThinning
  24. end;
  25.  
  26. (* ASUMPTION: match is only used with TOP signature. 
  27.  * This condition ensures a correct determination of the parent of functors
  28.  * which must contain the structure resulting of the matching 
  29.  *)
  30.  
  31. structure SigMatch : SIGMATCH =
  32. struct
  33.   open Modules ModuleUtil Types TypesUtil Variables PrettyPrint ErrorMsg Access
  34.        Instantiate Extern
  35.  
  36.   val BogusTy = UNDEFty (*** this is just a place holder in VALtrans when 
  37.                              the access is not INLINE and the 3rd componont
  38.                              is NONE.  ***)
  39.  
  40.   (* checkSharing: check sharing constraints.  Takes a structure
  41.      environment, a list of structure sharing constraints, a list
  42.      of type sharing constraints, an error function, and a symbolic
  43.      path as arguments.  The symbolic path is the path to this
  44.      structure: it is prefixed to symbolic paths within this
  45.      structure when error messages are printed.*)
  46.  
  47.   fun checkSharing(str : Structure, fullEnv : Modules.env,
  48.            sConstraints:{internal:spath list,
  49.                  external: Structure option} list,
  50.            tConstraints:{internal:spath list,
  51.                  external: Types.tycon option} list,
  52.             err) =
  53.     let fun f (lookup : spath ->'a, printName : ppstream -> 'a -> unit,
  54.            eq : 'a * 'a -> bool, errName:string)
  55.               ({internal:spath list,external : 'a option}) =
  56.          let fun g first =
  57.          let fun check x =
  58.          if eq(lookup x,first)
  59.             then ()
  60.             else (err COMPLAIN (errName^" sharing violation")
  61.                    (fn ppstrm =>
  62.                 (add_newline ppstrm; printName ppstrm first;
  63.                  add_string ppstrm " # "; PPUtil.ppSymPath ppstrm x)))
  64.          in app check internal
  65.          end
  66.       in case (internal,external)
  67.            of (l,SOME i) => g i
  68.             | (h::t,NONE) => g (lookup h)
  69.                 | (nil,NONE) => ()
  70.          end
  71.        val checkStructure = f (fn x => (fn STRvar{binding,...} => binding)
  72.                            (lookBindingSTR(str,x)),
  73.                    fn ppstrm => fn x =>
  74.                      PPBasics.ppStructureName ppstrm (fullEnv,x),
  75.                    eqOrigin,"structure")
  76.        val checkType = f (fn x => lookBindingTYC(str,x),
  77.               fn ppstrm => fn tyc => PPType.ppTycon fullEnv ppstrm tyc,
  78.               equalTycon,"type")
  79.     in app checkStructure sConstraints;
  80.        app checkType tConstraints
  81.     end
  82.  
  83.   fun compareTypes (env:Modules.env,err) (spec: ty, actual:ty,name) : unit =
  84.     if TypesUtil.compareTypes{spec=spec,actual=actual} then ()
  85.     else err COMPLAIN "value type in structure doesn't match signature spec"
  86.        (fn ppstrm =>
  87.         (PPType.resetPPType();
  88.          add_newline ppstrm;
  89.          app (add_string ppstrm) ["  name: ", Symbol.name name];
  90.          add_newline ppstrm;
  91.          add_string ppstrm "spec:   ";
  92.          PPType.ppType env ppstrm spec;
  93.          add_newline ppstrm;
  94.          add_string ppstrm "actual: ";
  95.          PPType.ppType env ppstrm actual))
  96.  
  97.       
  98.   fun conforming(INSTANCE{sign=SIG{stamp,kind=ref(TOP _),...},...},
  99.                SIG{stamp=stamp',kind=ref(TOP _),...}) = stamp=stamp'
  100.     | conforming _ = false
  101.  
  102.   fun match1 _ {str=ERROR_STR,...} = (ERROR_STR,NONE)
  103.     | match1 _ {str,sign=FULL_SIG,...} = (str,NONE)
  104.     | match1 _ {str,sign=ERROR_SIG,...} = (str,NONE)
  105.     | match1 (context: (Structure Array.array * Functor Array.array
  106.                         * tycon Array.array) option) 
  107.               {sign as SIG{symbols,env,kind,...},str,spath,
  108.                scope,err,printEnv,abstract,self,parent_sig,arg_option}
  109.                 : Structure * thinning =
  110.       if conforming(str,sign)
  111.       then ((if abstract then instantiate (sign, spath, scope,err)
  112.                     else str(* Could copy with new spath. *)),
  113.             NONE)
  114.       else
  115.       let val v = Access.mkLvar() (* local lvar for accessing str *)
  116.       val fullEnv = Env.atop(makeEnv(str,[v]),printEnv)
  117.            (* used for printing error msgs *)
  118.       val newContext as (subStrs,subFcts,types) = 
  119.         case (context,!kind)
  120.           of (_, TOP{strcount,typecount,fctcount,...}) =>
  121.              (Array.array(strcount,ERROR_STR),
  122.               Array.array(fctcount,ERROR_FCT),
  123.               Array.array(typecount,ERRORtyc))
  124.            | (SOME st, EMBEDDED) => st
  125.            | _ => impossible "Sigmatch.match1"
  126.       val (self',oldEnv) = 
  127.         if self then
  128.               case str
  129.           of INSTANCE{sign=SIG{env=str_env,...},subStrs,...} =>
  130.             (false,SOME (str_env,!env,subStrs))
  131.            | INSTANCE _ => (false,NONE)
  132.            | _ => (true,NONE)
  133.             else (false,NONE)
  134.       val newstr = INSTANCE{sign=sign,
  135.                 subStrs=subStrs,
  136.                                 subFcts=subFcts,
  137.                 types=types,
  138.                 path=spath,
  139.                 origin =
  140.                    if self' then SELF(Stamps.newStamp scope ())
  141.                    else ModuleUtil.getOrigin str}
  142.  
  143.           val new_parent_sig = 
  144.             case !kind
  145.             of TOP _ => newstr
  146.              | EMBEDDED => parent_sig
  147.          | IRRELEVANT => newstr
  148.           val complain = fn s => err COMPLAIN s nullErrorBody
  149.           val compare = compareTypes(fullEnv,err)
  150.           val transType' = ModuleUtil.transType newstr
  151.  
  152.           (* findComponent: Given a binding specification, find the actual
  153.              binding in a structure.  If the binding is not there, print an
  154.              error message and raise the exception Error.
  155.  
  156.              We must handle exception bindings specially, since they are
  157.              in the name space for constructors.  When we search for an
  158.              actual exception binding, we may find a constructor binding
  159.              instead.  For bindings in other namespaces, we will never
  160.              accidentally find bindings in other name spaces. *)
  161.  
  162.           (* declare type *)
  163.  
  164.           val findComponent =
  165.             let val complainMissing =
  166.           fn (UnboundComponent _,name,namespace) =>
  167.                       (complain("unmatched "^namespace^" spec: "^
  168.                 Symbol.name name);
  169.                        raise Error)
  170.                    | (ErrorStructure,_,_)  => raise Error
  171.                    | (exn,_,_) => raise exn
  172.                 val isExn = fn DATACON {rep,...} =>
  173.                       case rep
  174.                   of VARIABLE _ => true
  175.                    | VARIABLEc _ => true
  176.                    | _ => false
  177.             in fn (CONbind(spec as (DATACON{rep,name,...}))) =>
  178.                   ((case lookBinding(str,[name],[v])
  179.             of (binding as (CONbind actual)) =>
  180.               if isExn spec=isExn actual then binding
  181.               else raise UnboundComponent []
  182.              | _ => raise UnboundComponent [])
  183.            handle exn => 
  184.                complainMissing(exn,name,
  185.                        if isExn spec
  186.                                            then "exception"
  187.                                            else "data constructor"))
  188.             (* we never check infix bindings; we can return anything
  189.             here *)
  190.         | (spec as FIXbind _) => spec
  191.         | (spec as STRbind(STRvar{name=id,...})) =>
  192.                      if id=name_A then (
  193.                (* note that the access is not modified so that we
  194.               have a true LVAR and not a slot *)
  195.                case arg_option
  196.                        of NONE => impossible "sigmatch: can't find the arg"
  197.             | SOME arg => STRbind arg)
  198.                      else 
  199.                (lookBinding (str,[id],[v])
  200.              handle exn => complainMissing(exn,id,"structure"))
  201.                 | spec =>
  202.                   let val (name,namespace) =
  203.                      case spec
  204.                      of (FCTbind(FCTvar{name=id,...})) =>
  205.               (id,"structure")
  206.                       | (TYCbind(FORMtyc{spec=sigTycon,...})) =>
  207.                                 (tycName sigTycon,"type")
  208.                       | (CONbind(DATACON{name,...})) =>
  209.                                 (name,"data constructor")
  210.                       | (VARbind(VALvar{name=[id],...})) => (id,"val")
  211.               | _ => impossible "SigMatch.findComponent"
  212.                   in lookBinding (str,[name],[v])
  213.              handle exn => complainMissing(exn,name,namespace)
  214.           end
  215.              end
  216.  
  217.     exception BadBinding;
  218.  
  219.         fun checkDataconSign(name,d1,d2) =
  220.              let fun ck(DATACON{rep=r1,name=n1,...},DATACON{rep=r2,...}) =
  221.                 if r1=r2 then ()
  222.                 else (err COMPLAIN ("The constructor "^Symbol.name n1^
  223.                                    " of datatype "^Symbol.name name^
  224.                                    "\nhas different representations in \
  225.                                    \the signature and the structure.  \n\
  226.                                    \Change the definition of the types \
  227.                                    \carried by the constructors in the\n\
  228.                                    \functor formal parameter and the functor \
  229.                                     \actual parameter so that\n\
  230.                                    \they are both abstract, or so that \
  231.                                    \neither is abstract.\n")
  232.                nullErrorBody;
  233.               raise BadBinding)
  234.            in List2.app2 ck (d1,d2) end
  235.  
  236.      (* compare datacon names of spec and actual datatype.  This
  237.         uses the fact that datacons have been sorted by name. *)
  238.      fun compareDcons(spec,actual) =
  239.          let fun comp(l1 as dc1::r1, l2 as dc2::r2, s_only, a_only) =
  240.              if Symbol.eq(dc1,dc2) then comp(r1,r2,s_only,a_only)
  241.              else if Symbol.symbolGt(dc1,dc2) then
  242.                comp(l1,r2,s_only,dc2::a_only)
  243.              else comp(r1,l2,dc1::s_only,a_only)
  244.            | comp([], [], s_only, a_only) = (rev s_only, rev a_only)
  245.            | comp([], r, s_only, a_only) = (rev s_only, rev a_only @ r)
  246.            | comp(r, [], s_only, a_only) = (rev s_only @ r, rev a_only)
  247.           in comp(spec,actual,[],[])
  248.          end
  249.  
  250.          fun checkTycBinding(specTycon,strTycon) =
  251.       let val name = fn () => Symbol.name(tycName specTycon)
  252.           fun complain' x = (complain x; raise BadBinding)
  253.           fun symbolsToString [] = ""
  254.         | symbolsToString [n] = Symbol.name n
  255.         | symbolsToString (n::r) =
  256.            implode(Symbol.name n ::
  257.                fold (fn(n,b) => (","::Symbol.name n::b)) r [])
  258.           fun dconName(DATACON{name,...}) = name
  259.           in case specTycon
  260.              of GENtyc {stamp=s,arity,kind,eq=ref eq,...} =>
  261.             (if arity <> tyconArity strTycon
  262.              then complain' ("tycon arity for "^name()
  263.                                     ^ " does not match specified arity")
  264.              else case (!kind, strTycon)
  265.             of (DATAtyc dcons,
  266.                 GENtyc{arity=a',kind=ref (DATAtyc dc'),...})=>
  267.                 (case compareDcons(map dconName dcons, map dconName dc')
  268.                   of ([],[]) => checkDataconSign(tycName specTycon,
  269.                                  dcons,dc')
  270.                    | (s_only, a_only) =>
  271.                       complain'(implode["datatype ",name(),
  272.                    " does not match specification\n",
  273.                    case s_only
  274.                     of [] => ""
  275.                      | _  =>
  276.                        implode["  constructors in spec only: ",
  277.                                symbolsToString s_only, "\n"],
  278.                    case a_only
  279.                     of [] => ""
  280.                      | _  =>
  281.                        implode["  constructors in actual only: ",
  282.                                symbolsToString a_only, "\n"]]))
  283.              | (DATAtyc _, _) => 
  284.                   complain' ("type "^name()^" must be a datatype")
  285.              | (FORMtyck, _) =>
  286.                  if eq=YES andalso not(EqTypes.isEqTycon strTycon)
  287.                   then complain'
  288.                       ("type "^name()^
  289.                        " must be an equality type")
  290.                   else ()
  291.                          | _ => impossible "checkTycBinding 1")
  292.               | ERRORtyc => raise BadBinding
  293.               | _ => ErrorMsg.impossible "checkTycBinding 2"
  294.            end
  295.  
  296.           (* checkSpec:  Check that a binding specification is matched by an
  297.              actual binding in a structure.  Fill in the instantiation vectors
  298.              for types and structures.*)
  299.  
  300.       fun checkSpec spec =
  301.             let val result = findComponent spec
  302.             in
  303.           case (spec,result) 
  304.         of (STRbind(STRvar{name=id,binding=STR_FORMAL{pos,spec,...},
  305.                                    ...}),
  306.             STRbind(STRvar{access,binding=str',...})) =>
  307.               let val (str,thin) =
  308.             if id = name_P then (str',NONE)
  309.                         else
  310.                           match1 (SOME newContext)
  311.                 {sign=spec, str=str', spath = id :: spath,
  312.                  scope=scope, err=err, parent_sig=new_parent_sig,
  313.                  printEnv = printEnv, abstract=false,
  314.                  self=false, arg_option = NONE}
  315.               in Array.update(subStrs,pos,str);
  316.              if (hidden id) then []
  317.                          else
  318.                            [case thin
  319.                 of NONE => VALtrans(access,BogusTy,NONE)
  320.                  | SOME(v,transl) => THINtrans(access,v,transl)]
  321.               end
  322.                  | (FCTbind(FCTvar{name=id,binding=FCT_FORMAL{pos,spec,...},
  323.                                    ...}),
  324.             FCTbind(FCTvar{access,binding=fct',...})) =>
  325.                       let val (fct,thin) = matchFct1
  326.                 {fsig=spec,
  327.                  fct=fct',
  328.                  spath = id :: spath,
  329.                  scope = scope,
  330.                  err=err,
  331.                              parent_sig = new_parent_sig,
  332.                  printEnv = printEnv,
  333.                  abstract=false,
  334.                  self=false}
  335.               in Array.update(subFcts,pos,fct);
  336.              case thin 
  337.                           of NONE => [VALtrans(access,BogusTy,NONE)]
  338.                | SOME(thinI,thinO) => 
  339.                                (case spec 
  340.                                 of FSIG{argument,...} => 
  341.                                        [FCTtrans(access,argument,thinI,thinO)]
  342.                                  | _ => impossible "sigmatch check-spec 324")
  343.               end
  344.          | (TYCbind(FORMtyc{pos,spec=sigTycon,...}),
  345.             TYCbind(strTycon)) =>
  346.                 ( ((checkTycBinding(sigTycon,strTycon);
  347.                 Array.update(types,pos,strTycon)
  348.                ) handle BadBinding =>
  349.                  Array.update(types,pos,ERRORtyc));
  350.              nil)
  351.          | (CONbind(DATACON{name,typ,const,...}),
  352.             CONbind(DATACON{typ=typ',rep,...})) =>
  353.                 (compare(transType' typ,typ',name);
  354.                       case rep
  355.                        of VARIABLE access => [VALtrans(access,typ',SOME typ)]
  356.                         | VARIABLEc access => [VALtrans(access,typ',SOME typ)]
  357.                         | _ => nil)
  358.          | (VARbind(VALvar{name=[name],typ,...}),a) =>
  359.             (case a
  360.                of VARbind(VALvar{access,typ=typ',...}) =>
  361.  
  362.                 (* no propagation of INLINE access!! *)
  363.  
  364.                (compare(transType' (!typ),!typ',name);
  365.                 [VALtrans(access,!typ',SOME(!typ))])
  366.             | CONbind(dcon as DATACON{typ=typ',...}) =>
  367.                 (compare(transType' (!typ),typ',name);
  368.                  [CONtrans(dcon,SOME(!typ))])
  369.             | _ => impossible "sigmatch.sml: 122")
  370.          | (FIXbind _,_) => nil (* nonchecked binding *)
  371.                  | _ => impossible "sigmatch.sml: 124"
  372.             end
  373.  
  374.       fun checkList (a::rest) =
  375.         (checkSpec (Env.look (!env,a))
  376.          handle Error => nil | Env.Unbound => impossible "checkList")
  377.          @ checkList rest
  378.         | checkList nil = nil
  379.  
  380.       val trans = checkList (!symbols)
  381.       val _ = case !kind
  382.               of TOP{sConstraints,tConstraints,...} =>
  383.                 checkSharing(newstr,fullEnv,sConstraints,tConstraints,err)
  384.            | EMBEDDED => ()
  385.            | IRRELEVANT => ()
  386.       val _ =
  387.         if self then (
  388.           case oldEnv
  389.           of SOME (env,sigenv,strs) => 
  390.            (* The meaning of this hack is the following:
  391.               If the structure is a self but belongs to a functor
  392.               then it may contain a useless and big INSTANCE used
  393.               as an intermediate structure for open.
  394.               This function destroys such instances and replace them
  395.               by a dummy structure. *)
  396.            let fun clrOpen n = (
  397.              case Array.sub(strs,n) 
  398.                  of INSTANCE{path as _ :: _, ...} =>
  399.                   if Symbol.eq(name_O,last path) then 
  400.                 (Array.update(strs,n,ERROR_STR);clrOpen (n+1))
  401.                   else clrOpen (n+1)
  402.               | _ =>  clrOpen (n+1)) handle Array.Subscript => ()
  403.                val thinenv = ref Env.empty
  404.                (* Note: it would be nice if Env.map gave also the
  405.               symbol to the argument function *)
  406.                val _ = 
  407.              Env.app 
  408.                (fn (name,_) =>
  409.                   thinenv := Env.bind(name,Env.look(!env,name),
  410.                               !thinenv)
  411.                   handle Env.Unbound => ())
  412.                sigenv
  413.            in env := Env.consolidate(!thinenv) ;  clrOpen 0 end
  414.            | NONE => ())
  415.         else ()
  416.       val str = if abstract then instantiate(sign,spath,scope,err)
  417.                            else newstr
  418.        in (str, SOME(v,trans))
  419.       end
  420.  
  421.   and matchFct1 {abstract,err,scope,spath,printEnv,self,
  422.                  parent_sig,fct,
  423.                  fsig=fsig as FSIG{paramName,argument=sig_arg,
  424.                                    body=sig_body,...}} =
  425.       let 
  426.          (* externalize the sharing constraints with the parent in the
  427.           * argument signature so that we can use instantiate *)
  428.           val arg_final = externalize_sharing name_P parent_sig sig_arg
  429.          (* instance of the argument *)
  430.           val inst_sig_arg = Instantiate.instantiate(arg_final,[],scope,err)
  431.           val arg_var = STRvar{access=PATH [], name=name_A,
  432.                    binding=inst_sig_arg}
  433.           val _ = update_structure name_P parent_sig inst_sig_arg
  434.          (* the corresponding version with the parent of the structure *)
  435.           val STRvar{binding=val_X,...} = lookBindingSTR(inst_sig_arg,[name_X])
  436.          (* we don't keep thinnings: thinin is a thinning against a dummy
  437.             structure we usually never build and thinout is discarded (if
  438.             we used one it would come with res_match *)
  439.           val (res,thinIn) =
  440.             ApplyFunctor.applyFunctorFull 
  441.               (fct, val_X, scope,spath,err,printEnv, match) 
  442.          (* matches the result against the body specification of the functor
  443.           * signature. The specif of the functor body must be a TOP to get
  444.           * a correct notion of parent_sig 
  445.       * we keep the thinning obtained *)
  446.           val (res_match,thinning) = 
  447.             match1 NONE 
  448.                    {abstract=abstract, err=err, scope=scope, spath=spath,
  449.                     printEnv=printEnv, self=false, parent_sig=ERROR_STR,
  450.                     sign=sig_body, str=res, arg_option=SOME arg_var}
  451.           val raw_fct = 
  452.             case fct 
  453.             of FCT_INSTANCE{fct,...} => fct
  454.              | fct => fct
  455.           val new_fct = 
  456.             FCT_INSTANCE{fct=raw_fct,fsig=fsig,parent=parent_sig}
  457.       in (new_fct,SOME(thinIn,thinning)) end
  458.     | matchFct1 {fsig=ERROR_FSIG,fct,...} = (fct,NONE)
  459.  
  460.   and match {abstract:bool,
  461.              err:ErrorMsg.complainer,
  462.              arg_option: structureVar option,
  463.              scope:Stamps.scope,
  464.              spath : Modules.spath,
  465.              printEnv: Modules.env,
  466.              self:bool,
  467.              sign:Modules.Signature,
  468.              str:Modules.Structure} 
  469.           = match1 NONE {abstract=abstract,err=err,scope=scope,spath=spath,
  470.                          printEnv=printEnv,self=self,arg_option=arg_option,
  471.                          parent_sig = ERROR_STR, sign=sign,str=str}
  472.   and matchFct {abstract,err,scope,spath,printEnv,self,fsig,fct} =
  473.     matchFct1 {abstract=abstract,err=err,scope=scope,printEnv=printEnv,
  474.                self=self,spath=spath,fsig=fsig,fct=fct, parent_sig=ERROR_STR}
  475. ;
  476.  
  477. end  (* structure SigMatch *)
  478.